package net.chensee.avastxa.common.socket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import net.chensee.avastxa.common.exception.ServerStopException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SocketServerStarter {
    private static final Logger logger = LoggerFactory.getLogger(SocketServerStarter.class);

    private int ioThreadNum;

    //内核为此套接口排队的最大连接个数，对于给定的监听套接口，内核要维护两个队列，未链接队列和已连接队列大小总和最大值
    private int backlog;

    private int port;

    private Channel channel;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ChannelHandler channelHandler;

    public static SocketServerStarter newInstance(int ioThreadNum, int backlog, int port) {
        return new SocketServerStarter(ioThreadNum, backlog, port);
    }

    public static SocketServerStarter newInstance(int ioThreadNum, int port) {
        return newInstance(ioThreadNum, 1024, port);
    }

    public SocketServerStarter(int ioThreadNum, int backlog, int port) {
        this.ioThreadNum = ioThreadNum;
        this.backlog = backlog;
        this.port = port;
    }

    public SocketServerStarter setInitialzer(ChannelHandler channelHandler) {
        this.channelHandler = channelHandler;
        return this;
    }

    public void start() throws InterruptedException {
        if (this.channelHandler == null) {
            logger.error("must initial socket handler");
            return ;
        }
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup(this.ioThreadNum);

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, backlog)
                //注意是childOption
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childHandler(this.channelHandler);

        channel = serverBootstrap.bind("127.0.0.1",port).sync().channel();

        logger.info("socket server listening on port "+ port + " and ready for connections...");

        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run(){
                //do shutdown staff
                SocketServerStarter.this.stop();
            }
        });
    }

    public void stop() {
        if (null == channel) {
            throw new ServerStopException();
        }
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        channel.closeFuture().syncUninterruptibly();
        bossGroup = null;
        workerGroup = null;
        channel = null;
    }
}
